/**
 * @description:
 * @file: vite.config.ts
 * @author: Evan
 * @date: 2025.04.08 10:37:24
 * @week: 周二
 * @version: V
 * */

import { defineConfig, loadEnv, ConfigEnv, UserConfigExport } from 'vite'
import vue from '@vitejs/plugin-vue'

// mock 接口模拟
import { viteMockServe } from 'vite-plugin-mock'

// 按需导入
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
import ElementPlus from 'unplugin-element-plus/vite'

// 自动导入Icon图标
import Icons from 'unplugin-icons/vite'
import IconsResolver from 'unplugin-icons/resolver'

// svg
import { createSvgIconsPlugin } from 'vite-plugin-svg-icons'

// 代码压缩
import viteCompression from 'vite-plugin-compression'

// css px 转 rem
// @ts-ignore
import postcssPluginPx2rem from 'postcss-plugin-px2rem'

// 检查更新
import { checkUpdate } from './plugin/check-update'

import path from 'path'
function resolve(url: string) {
  return path.resolve(__dirname, url)
}

// https://vite.dev/config/
export default ({ mode }: ConfigEnv): UserConfigExport => {
  const env = loadEnv(mode, __dirname)
  const isProduction = env.VITE_MODE === 'production'
  console.log('生产环境:', isProduction)
  return defineConfig({
    // 插件
    plugins: [
      vue(),

      checkUpdate({
        // 相对于插件文件的位置
        jsonPath: './public/sys/manifest.json'
      }),

      // mock服务
      viteMockServe({
        // 是否读取ts模块，为true时不可读取js文件
        supportTs: false,
        // 是否在控制台显示请求日志
        logger: true,
        // 置模拟数据的存储文件夹，如果不是index.js需要写明完整路径
        mockPath: './src/mock/',
        // 设置打包是否启用 mock 功能
        prodEnabled: true,
        // 设置是否启用本地mock文件
        localEnabled: true,
        // 设置是否监视mockPath对应的文件夹内文件中的更改
        watchFiles: true,
        // --如果生产环境开启了 mock 功能,即 prodEnabled=true.则该代码会被注入到 injectFile 对应的文件的底部。默认为main.{ts,js}。
        // 这样做的好处是,可以动态控制生产环境是否开启 mock 且在没有开启的时候 mock.js 不会被打包。
        // 如果代码直接写在main.ts内，则不管有没有开启,最终的打包都会包含mock.js
        injectFile: 'main.ts',
        // injectCode 代码注入的文件,默认为项目根目录下src/main.{ts,js}
        injectCode: `
          import { setupProdMockServer } from './mock/mockProdServer'
          setupProdMockServer()
        `
      }),

      // 按需导入
      AutoImport({
        resolvers: [
          ElementPlusResolver({ importStyle: 'sass' }), // 此处需配置 importStyle 否则 替换 element-plus 全局scss变量不生效
          // 自动导入图标组件
          IconsResolver({
            prefix: 'Icon'
          })
        ],
        dts: './types/auto-imports.d.ts',
        imports: ['vue', 'vue-router'],
        // 解决eslint报错问题
        eslintrc: {
          // 这里先设置成true然后npm run dev 运行之后会生成 .eslintrc-auto-import.json 文件之后，在改为false
          enabled: false,
          filepath: './types/.eslintrc-auto-import.json', // 生成的文件路径
          globalsPropValue: true
        }
      }),
      Components({
        dts: './types/components.d.ts',
        resolvers: [
          // 组件自动导入
          ElementPlusResolver({ importStyle: 'sass' }), // 此处需配置 importStyle 否则 替换 element-plus 全局scss变量不生效
          // 自动注册图标组件
          IconsResolver({
            // 修改Icon组件前缀，不设置则默认为i,禁用则设置为false
            prefix: 'icon',
            // 指定collection，即指定为elementplus图标集ep
            // 格式 icon-ep-图表名称
            enabledCollections: ['ep']
          })
        ]
      }),

      // 来编译所有应用 scss 变量的组件
      ElementPlus({
        useSource: true
      }),
      // Icons图标自动下载
      Icons({
        autoInstall: true
      }),
      // svg
      createSvgIconsPlugin({
        // 指定需要缓存的图标文件夹
        iconDirs: [
          resolve('src/assets/svg'),
          resolve('src/layout/icon'),
          resolve('src/components/icon')
        ],
        // 指定symbolId格式
        // symbolId: 'icon-[name]',
        symbolId: 'icon-[dir]-[name]',
        // body-last|body-first默认body-last
        inject: 'body-last',
        // custom dom id
        customDomId: '__svg__icons__dom__'
      }),
      // 压缩配置
      viteCompression({
        algorithm: 'gzip', // gzip 压缩
        ext: '.gz'
      })
    ],

    // 基础路径
    base: '/',

    // 起个别名，在引用资源时，可以用‘@/资源路径’直接访问
    resolve: {
      alias: {
        '@': resolve('src')
      }
    },

    // 打包配置
    build: {
      target: 'modules',
      outDir: 'dist', //指定输出路径
      assetsDir: 'assets/js', // 指定生成静态资源的存放路径
      minify: 'terser', // 混淆器，terser构建后文件体积更小
      sourcemap: isProduction, // 生成 source map
      terserOptions: {
        // 打包时清除 console 和 debug 相关代码
        compress: {
          drop_console: !isProduction,
          drop_debugger: !isProduction
          // pure_funcs: ['console.log']
        }
      },

      rollupOptions: {
        output: {
          // 打包分割
          manualChunks: id => {
            if (id.includes('node_modules')) {
              return id.toString().split('node_modules/')[1].split('/')[0].toString()
            }
            if (id.includes('src/common')) {
              return 'common'
            }
          },
          // 资源文件像 字体，图片等
          assetFileNames: info => {
            const name = info.name as string
            // 匹配资源文件后缀
            if (/\.(mp4|webm|ogg|mp3|wav|flac|aac)$/.test(name)) {
              // 创建media文件夹存放匹配的资源文件,name为该文件的原名，hash为哈希值，ext为文件后缀名，以[name]-[hash].[ext]命名规则
              return `media/[name]-[hash].[ext]`
            }
            if (/\.(jpg|png|webp|jpeg)$/.test(name)) {
              return `imgs/[name]-[hash].[ext]`
            }
            if (/\.(svg)$/.test(name)) {
              return `assets/svg/[name]-[hash].[ext]`
            }
            if (/\.(css|less|sass|scss)$/.test(name)) {
              return `assets/css/[name]-[hash].[ext]`
            }
            return `assets/[name]-[hash].[ext]` // 不匹配的资源文件存放至assets，以[name]-[hash].[ext]命名规则，注意两处的命名规则不同
          }
        }
      }
    },

    // css预处理器
    css: {
      // 全局样式配置
      preprocessorOptions: {
        // 全局样式，存放一些主题等变量
        scss: {
          // 替换 Element Plus 内置的 scss 变量
          additionalData: `@use "@/assets/element/index.scss" as *;`
        }
      },

      postcss: {
        plugins: [
          postcssPluginPx2rem({
            rootValue: 192, //换算基数，设计宽度/10
            unitPrecision: 5, //允许REM单位增长到的十进制数字，其实就是精度控制
            // propWhiteList: [], // 默认值是一个空数组，这意味着禁用白名单并启用所有属性。
            // propBlackList: [], // 黑名单
            exclude: /(views\/large)/, //默认false，可以（reg）利用正则表达式排除某些文件夹的方法，例如/(node_module)/ 。如果想把前端UI框架内的px也转换成rem，请把此属性设为默认值
            // 要忽略并保留为px的选择器
            selectorBlackList: ['no-rem'],
            // ignoreIdentifier: false, //（boolean/string）忽略单个属性的方法，启用ignoreidentifier后，replace将自动设置为true。
            // replace: true, // （布尔值）替换包含REM的规则，而不是添加回退。
            mediaQuery: false, //（布尔值）允许在媒体查询中转换px
            minPixelValue: 2 //设置要替换的最小像素值(3px会被转rem)。 默认 0
          })
        ]
      }
    },

    // 服务器配置
    server: {
      host: '0.0.0.0',
      port: 9002,
      headers: {
        // 强制浏览器不缓存
        'Cache-Control': 'no-cache',
        'Access-Control-Allow-Origin': '*'
      },

      // 设置反向代理，跨域
      proxy: {
        '/api': {
          // 后台地址
          target: env.VITE_APP_API_URL,
          changeOrigin: true,
          rewrite: path => path.replace(/^\/api/, '')
        }
      }
    },

    // 预览服务
    preview: {
      port: 9003
    }
  })
}
